package vip.aster.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.aster.common.constant.CacheConstants;
import vip.aster.common.constant.Constants;
import vip.aster.common.constant.enums.StatusEnum;
import vip.aster.common.exception.BusinessException;
import vip.aster.common.utils.CacheUtils;
import vip.aster.common.utils.PageInfo;
import vip.aster.common.utils.RSAEncrypt;
import vip.aster.framework.i18n.MessageUtils;
import vip.aster.framework.mybatis.enums.DataScopeEnum;
import vip.aster.system.entity.*;
import vip.aster.system.mapper.*;
import vip.aster.system.query.SysTenantQuery;
import vip.aster.system.service.*;
import vip.aster.system.vo.SysDictTypeVO;
import vip.aster.system.vo.SysTenantVO;
import vip.aster.tenant.constants.TenantConstants;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 租户 服务实现类
 * </P>
 *
 * @author Aster lipian1004@163.com
 * @since 2024-03-25 14:46:59
 */
@Service
@AllArgsConstructor
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant> implements SysTenantService {
    private SysTenantMapper sysTenantMapper;
    private SysTenantPackageMapper sysTenantPackageMapper;
    private SysRoleMapper sysRoleMapper;
    private SysRoleMenuService sysRoleMenuService;
    private SysOrgMapper sysOrgMapper;
    private SysRoleOrgMapper sysRoleOrgMapper;
    private SysUserMapper sysUserMapper;
    private SysUserRoleMapper sysUserRoleMapper;
    private SysDictTypeService dictTypeService;
    private SysDictDataService dictDataService;
    private SysConfigService sysConfigService;
    private PasswordEncoder passwordEncoder;

    @Override
    public PageInfo<SysTenantVO> pageList(SysTenantQuery query) {
        Page<SysTenant> page = new Page<>(query.getPageNum(), query.getPageSize());
        Page<SysTenant> pageList = sysTenantMapper.selectPage(page, getWrapper(query));
        return new PageInfo<>(SysTenantVO.convertList(pageList.getRecords()), pageList.getTotal());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(SysTenantVO vo) throws Exception {
        SysTenant entity = vo.reconvert();

        if (StrUtil.isNotBlank(entity.getId())) {
            sysTenantMapper.updateById(entity);
        } else {
            // 获取所有租户编号
            List<String> tenantIds = this.list().stream().map(SysTenant::getId).toList();
            // 生成租户编号
            String tenantId = generateTenantId(tenantIds);
            entity.setId(tenantId);

            int insert = sysTenantMapper.insert(entity);
            if (insert < 1) {
                throw new BusinessException(MessageUtils.message("tenant.create.error"));
            }

            vo.setId(entity.getId());

            // 创建部门: 公司名是部门名称
            SysOrg dept = new SysOrg();
            dept.setTenantId(tenantId);
            dept.setOrgName(vo.getCompanyName());
            dept.setPid(Constants.ROOT_NODE);
            dept.setSort(1);
            dept.setStatus(StatusEnum.ENABLE.getValue());
            sysOrgMapper.insert(dept);

            String orgId = dept.getId();

            // 根据套餐创建角色
            String roleId = createTenantRole(tenantId, vo.getPackageId(), orgId);

            // 角色和部门关联表
            SysRoleOrg roleDept = new SysRoleOrg();
            roleDept.setRoleId(roleId);
            roleDept.setOrgId(orgId);
            sysRoleOrgMapper.insert(roleDept);

            // 解密密码
            String privateKey = CacheUtils.get(CacheConstants.SECRET_KEY, CacheConstants.PRIVATE_KEY, String.class);
            String password = RSAEncrypt.decrypt(vo.getPassword(), privateKey);
            // 创建系统用户
            SysUser user = new SysUser();
            user.setTenantId(tenantId);
            user.setUsername(vo.getUsername());
            user.setNickName(vo.getUsername());
            user.setPassword(passwordEncoder.encode(password));
            user.setOrgId(orgId);
            user.setStatus(StatusEnum.ENABLE.getValue());
            sysUserMapper.insert(user);

            // 用户角色关联
            SysUserRole userRole = new SysUserRole();
            userRole.setUserId(user.getId());
            userRole.setRoleId(roleId);
            sysUserRoleMapper.insert(userRole);

            // 默认租户id
            String defaultTenantId = TenantConstants.DEFAULT_TENANT_ID;

            // 系统参数
            List<SysConfig> sysConfigList = sysConfigService.list(
                    new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getTenantId, defaultTenantId));
            for (SysConfig config : sysConfigList) {
                config.setId(null);
                config.setTenantId(tenantId);
            }
            sysConfigService.saveBatch(sysConfigList);

            DefaultIdentifierGenerator identifierGenerator = DefaultIdentifierGenerator.getInstance();

            // 字典项
            List<SysDictTypeVO> list = dictTypeService.getDictAll();
            List<SysDictType> typeList = new ArrayList<>();
            List<SysDictData> dataList = new ArrayList<>();
            for (SysDictTypeVO dictType : list) {
                // 生成type主键
                String typeId = identifierGenerator.nextId(new Object()).toString();
                SysDictType sysDictType = dictType.reconvert();
                sysDictType.setId(typeId);
                sysDictType.setTenantId(tenantId);
                typeList.add(sysDictType);
                dictType.getDataList().forEach(d -> {
                    String dataId = identifierGenerator.nextId(new Object()).toString();
                    SysDictData sysDictData = d.reconvert();
                    sysDictData.setId(dataId);
                    sysDictData.setDictTypeId(typeId);
                    sysDictData.setTenantId(tenantId);
                    dataList.add(sysDictData);
                });
            }
            dictTypeService.saveBatch(typeList);
            dictDataService.saveBatch(dataList);

        }
    }

    @Override
    public List<SysTenantVO> getList() {
        LambdaQueryWrapper<SysTenant> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysTenant::getStatus, StatusEnum.ENABLE.getValue());
        queryWrapper.and(qw -> qw.isNull(SysTenant::getExpireTime).
                or()
                .ge(SysTenant::getExpireTime, LocalDateTime.now()));
        List<SysTenant> list = this.list(queryWrapper);
        return SysTenantVO.convertList(list);
    }

    @Override
    public boolean isTenantAdmin(String userId, String tenantId) {
        SysRole role = sysRoleMapper.selectOne(
                new LambdaQueryWrapper<SysRole>().eq(SysRole::getRoleCode, TenantConstants.TENANT_ADMIN_ROLE_KEY));

        List<SysUserRole> list = sysUserRoleMapper.selectList(
                new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, role.getId()));
        if (CollUtil.isEmpty(list)) {
            return false;
        }
        return list.stream().anyMatch(r -> r.getUserId().equals(userId));
    }

    private LambdaQueryWrapper<SysTenant> getWrapper(SysTenantQuery query) {
        LambdaQueryWrapper<SysTenant> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StrUtil.isNotBlank(query.getContactUserName()), SysTenant::getContactUserName, query.getContactUserName());
        wrapper.like(StrUtil.isNotBlank(query.getCompanyName()), SysTenant::getCompanyName, query.getCompanyName());
        wrapper.eq(StrUtil.isNotBlank(query.getStatus()), SysTenant::getStatus, query.getStatus());
        return wrapper;
    }

    /**
     * 生成租户id
     *
     * @param tenantIds 已有租户id列表
     * @return 租户id
     */
    private String generateTenantId(List<String> tenantIds) {
        // 随机生成6位
        String numbers = RandomUtil.randomNumbers(6);
        // 判断是否存在，如果存在则重新生成
        if (tenantIds.contains(numbers)) {
            generateTenantId(tenantIds);
        }
        return numbers;
    }

    /**
     * 根据租户菜单创建租户角色
     *
     * @param tenantId  租户编号
     * @param packageId 租户套餐id
     * @param orgId     机构id
     * @return 角色id
     */
    private String createTenantRole(String tenantId, String packageId, String orgId) {
        // 获取租户套餐
        SysTenantPackage tenantPackage = sysTenantPackageMapper.selectById(packageId);
        if (ObjectUtil.isNull(tenantPackage)) {
            throw new BusinessException(MessageUtils.message("tenant.package.not.exists"));
        }
        // 获取套餐菜单id
        List<String> menuIds = StrUtil.split(tenantPackage.getMenuIds(), ",");

        // 创建角色
        SysRole role = new SysRole();
        role.setTenantId(tenantId);
        role.setRoleName(TenantConstants.TENANT_ADMIN_ROLE_NAME);
        role.setRoleCode(TenantConstants.TENANT_ADMIN_ROLE_KEY);
        role.setDataScope(DataScopeEnum.ALL.getValue());
        role.setOrgId(orgId);
        role.setSort(1);
        role.setStatus(StatusEnum.ENABLE.getValue());
        sysRoleMapper.insert(role);
        String roleId = role.getId();

        // 创建角色菜单
        List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
        menuIds.forEach(menuId -> {
            SysRoleMenu roleMenu = new SysRoleMenu();
            roleMenu.setRoleId(roleId);
            roleMenu.setMenuId(menuId);
            roleMenus.add(roleMenu);
        });
        sysRoleMenuService.saveBatch(roleMenus);

        return roleId;
    }

}